package org.nod.atgm;

import java.lang.reflect.Field;

import javax.microedition.khronos.egl.EGL10;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.egl.EGLDisplay;
import javax.microedition.khronos.opengles.GL10;

import android.app.Activity;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.opengl.GLSurfaceView;
import android.os.Bundle;
import android.view.Display;
import android.view.MotionEvent;
import android.view.Surface;
import android.view.Window;
import android.view.WindowManager;

import com.threed.jpct.FrameBuffer;
import com.threed.jpct.Logger;
import com.threed.jpct.RGBColor;
import com.threed.jpct.World;
import com.threed.jpct.util.MemoryHelper;
import com.threed.jpct.util.SkyBox;

public class AtgmActivity extends Activity implements SensorEventListener{
	// Used to handle pause and resume...
	private static AtgmActivity master = null;

	private GLSurfaceView mGLView;
	private MyRenderer renderer = null;
	private FrameBuffer fb = null;
	private World world = null;
	private RGBColor back = new RGBColor(50, 50, 100);

	private float touchTurn = 0;
	private float touchTurnUp = 0;

	private int fps = 0;

	

	 private SensorManager mSensorManager;
//	 private float[] rotationMatrix = new float[16];
//	 private float[] accelGData = new float[3];
//	 private float[] bufferedAccelGData = new float[3];
//	 private float[] magnetData = new float[3];
//	 private float[] bufferedMagnetData = new float[3];
//	 private float[] orientationData = new float[3];
//
//	private boolean landscape;

	private GameManager gameManager;

	private Display mDisplay;

	private float mSensorX;

	private float mSensorY;

//	private Vibrator vibrator;


	private SkyBox skyBox;


	protected void onCreate(Bundle savedInstanceState) {

		Logger.log("onCreate");
		requestWindowFeature(Window.FEATURE_NO_TITLE);
		getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);

		if (master != null) {
			copy(master);
		}
		
		super.onCreate(savedInstanceState);
		mGLView = new GLSurfaceView(getApplication());
        mDisplay = ((WindowManager) getSystemService(WINDOW_SERVICE)).getDefaultDisplay();
//        vibrator = ((Vibrator) getSystemService(VIBRATOR_SERVICE));
		mGLView.setEGLConfigChooser(new GLSurfaceView.EGLConfigChooser() {
			public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) {
				// Ensure that we get a 16bit framebuffer. Otherwise, we'll fall
				// back to Pixelflinger on some device (read: Samsung I7500)
				int[] attributes = new int[] { EGL10.EGL_DEPTH_SIZE, 16, EGL10.EGL_NONE };
				EGLConfig[] configs = new EGLConfig[1];
				int[] result = new int[1];
				egl.eglChooseConfig(display, attributes, configs, 1, result);
				return configs[0];
			}
		});

		renderer = new MyRenderer();
		mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);

		mGLView.setRenderer(renderer);
		setContentView(mGLView);
	}

	@Override
	protected void onStop() {
		super.onStop();
	}

	private void copy(Object src) {
		try {
			Logger.log("Copying data from master Activity!");
			Field[] fs = src.getClass().getDeclaredFields();
			for (Field f : fs) {
				f.setAccessible(true);
				f.set(this, f.get(src));
			}
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	public boolean onTouchEvent(MotionEvent me) {

		if (me.getAction() == MotionEvent.ACTION_DOWN) {
//			xpos = me.getX();
//			ypos = me.getY();
			return true;
		}

		if (me.getAction() == MotionEvent.ACTION_UP) {
//			xpos = -1;
//			ypos = -1;
//			touchTurn = 0;
//			touchTurnUp = 0;
			if (gameManager != null)
				gameManager.handleTouchUp(me);
			return true;
		}

		if (me.getAction() == MotionEvent.ACTION_MOVE) {
//			float xd = me.getX() - xpos;
//			float yd = me.getY() - ypos;
//
//			xpos = me.getX();
//			ypos = me.getY();
//
//			touchTurn = xd / -100f;
//			touchTurnUp = yd / -100f;
			return true;
		}

		try {
			Thread.sleep(15);
		} catch (Exception e) {
			// No need for this...
		}

		return super.onTouchEvent(me);
	}

	protected boolean isFullscreenOpaque() {
		return true;
	}
	
	class MyRenderer implements GLSurfaceView.Renderer {

		private long time = System.currentTimeMillis();
		public MyRenderer() {
		}

		public void onSurfaceChanged(GL10 gl, int w, int h) {
			if (fb != null) {
				fb.dispose();
			}
			fb = new FrameBuffer(gl, w, h);

			if (master == null) {

				gameManager = new GameManager(AtgmActivity.this);
				world = gameManager.createWorld();
				skyBox = gameManager.getSkyBox();

//				cube = Primitives.getCube(10);
//				cube.calcTextureWrapSpherical();
//				cube.setTexture("texture");
//				cube.strip();
//				cube.build();
//
//				world.addObject(cube);

//				Camera cam = world.getCamera();
//				cam.moveCamera(Camera.CAMERA_MOVEOUT, 50);
//				cam.lookAt(cube.getTransformedCenter());
//
//				SimpleVector sv = new SimpleVector();
//				sv.set(cube.getTransformedCenter());
//				sv.y -= 100;
//				sv.z -= 100;
//				sun.setPosition(sv);
				MemoryHelper.compact();
				gameManager.startGameLoop();

				if (master == null) {
					Logger.log("Saving master Activity!");
					master = AtgmActivity.this;
				}
			}
		}

		public void onSurfaceCreated(GL10 gl, EGLConfig config) {
		}

		public void onDrawFrame(GL10 gl) {
			gameManager.updateUI();
			if (touchTurn != 0) {
				touchTurn = 0;
			}

			if (touchTurnUp != 0) {
				touchTurnUp = 0;
			}

			fb.clear(back);
			skyBox.render(world,fb);
			world.renderScene(fb);
			world.draw(fb);
			gameManager.postWorldDraw(fb);
			fb.display();
			// ... Draw here your own 3D world
//			fb.clear();
//			world.renderScene(fb);
//			world.draw(fb);
//			blitNumber(lfps, 5, 5);
//			fb.display();			
//		}



			if (System.currentTimeMillis() - time >= 1000) {
				Logger.log(fps + "fps");
				fps = 0;
				time = System.currentTimeMillis();
			}
			fps++;
		}
	}

	@Override
	public void onAccuracyChanged(Sensor sensor, int accuracy) {
		// TODO Auto-generated method stub
		
	}

	@Override
    public void onSensorChanged(SensorEvent event) {
        if (event.sensor.getType() != Sensor.TYPE_ACCELEROMETER)
            return;
        /*
         * record the accelerometer data, the event's timestamp as well as
         * the current time. The latter is needed so we can calculate the
         * "present" time during rendering. In this application, we need to
         * take into account how the screen is rotated with respect to the
         * sensors (which always return data in a coordinate space aligned
         * to with the screen in its native orientation).
         */

        switch (mDisplay.getRotation()) {
            case Surface.ROTATION_0:
                mSensorX = event.values[0];
                mSensorY = event.values[1];
                break;
            case Surface.ROTATION_90:
                mSensorX = -event.values[1];
                mSensorY = event.values[0];
                break;
            case Surface.ROTATION_180:
                mSensorX = -event.values[0];
                mSensorY = -event.values[1];
                break;
            case Surface.ROTATION_270:
                mSensorX = event.values[1];
                mSensorY = -event.values[0];
                break;
        }
        if (gameManager != null)
        	gameManager.handleSensor(mSensorX, mSensorY);
//        mSensorTimeStamp = event.timestamp;
//        mCpuTimeStamp = System.nanoTime();
    }

	@Override
	protected void onResume() {
		// Ideally a game should implement onResume() and onPause()
		// to take appropriate action when the activity looses focus
		super.onResume();
		mGLView.onResume();

//		if (((WindowManager) getSystemService(WINDOW_SERVICE)).getDefaultDisplay().getOrientation() == 1) {
//			landscape = true;
//		} else {
//			landscape = false;
//		}

		mSensorManager.registerListener(this, mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), SensorManager.SENSOR_DELAY_GAME);
		mSensorManager.registerListener(this, mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD), SensorManager.SENSOR_DELAY_GAME);
		mSensorManager.registerListener(this, mSensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION), SensorManager.SENSOR_DELAY_GAME);
	}

	@Override
	protected void onPause() {
		// Ideally a game should implement onResume() and onPause()
		// to take appropriate action when the activity looses focus
		super.onPause();
		mGLView.onPause();
		mSensorManager.unregisterListener(this);
	}


}